package com.yq.skinlib.manage;

import android.app.Application;
import android.content.Context;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.res.ColorStateList;
import android.content.res.Resources;
import android.graphics.drawable.Drawable;
import android.os.AsyncTask;
import android.text.TextUtils;
import android.util.SparseArray;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;

import com.yq.skinlib.observe.SkinActivityLifecycle;
import com.yq.skinlib.observe.SkinObservable;
import com.yq.skinlib.sizechange.ChangeTextSizeManager;
import com.yq.skinlib.utils.SkinConfigEntity;
import com.yq.skinlib.utils.SkinInfo;
import com.yq.skinlib.utils.SkinPreference;


public class SkinCompatManager extends SkinObservable {
    //官方红
    public static final int SKIN_LOADER_STRATEGY_NONE = 0;
    public static final int SKIN_LOADER_STRATEGY_ASSETS = 2;
    //远程下载
    public static final int SKIN_LOADER_STRATEGY_BUILD_IN = 1;
    //夜间模式
    public static final int SKIN_LOADER_STRATEGY_PREFIX_BUILD_IN = 3;
    private static volatile SkinCompatManager sInstance;
    private final Object mLock = new Object();
    private final Context mAppContext;
    private boolean mLoading = false;
    private SparseArray<SkinLoaderStrategy> mStrategyMap = new SparseArray<>();
    private boolean mSkinAllActivityEnable = true;
    private static boolean needClearZip = false;

    private SkinConfigEntity mSkinConfig;

    @Nullable
    public SkinConfigEntity getSkinConfig() {
        return mSkinConfig;
    }

    public void setSkinConfig(SkinConfigEntity skinConfig) {
        mSkinConfig = skinConfig;
    }

    /**
     * 皮肤包加载监听.
     */
    public interface SkinLoaderListener {
        /**
         * 开始加载.
         */
        void onStart();

        /**
         * 加载成功.
         */
        void onSuccess();

        /**
         * 加载失败.
         *
         * @param errMsg 错误信息.
         */
        void onFailed(String errMsg);
    }

    /**
     * 皮肤包加载策略.
     */
    public interface SkinLoaderStrategy {
        /**
         * 加载皮肤包.
         *
         * @param context  {@link Context}
         * @param skinName 皮肤包名称.
         * @return 加载成功，返回皮肤包名称；失败，则返回空。
         */
        String loadSkinInBackground(Context context, String skinName);

        /**
         * 根据应用中的资源ID，获取皮肤包相应资源的资源名.
         *
         * @param context  {@link Context}
         * @param skinName 皮肤包名称.
         * @param resId    应用中需要换肤的资源ID.
         * @return 皮肤包中相应的资源名.
         */
        String getTargetResourceEntryName(Context context, String skinName, int resId);

        /**
         * 开发者可以拦截应用中的资源ID，返回对应color值。
         *
         * @param context  {@link Context}
         * @param skinName 皮肤包名称.
         * @param resId    应用中需要换肤的资源ID.
         * @return 获得拦截后的颜色值，添加到ColorStateList的defaultColor中。不需要拦截，则返回空
         */
        ColorStateList getColor(Context context, String skinName, int resId);

        /**
         * 开发者可以拦截应用中的资源ID，返回对应ColorStateList。
         *
         * @param context  {@link Context}
         * @param skinName 皮肤包名称.
         * @param resId    应用中需要换肤的资源ID.
         * @return 返回对应ColorStateList。不需要拦截，则返回空
         */
        ColorStateList getColorStateList(Context context, String skinName, int resId);

        /**
         * 开发者可以拦截应用中的资源ID，返回对应Drawable。
         *
         * @param context  {@link Context}
         * @param skinName 皮肤包名称.
         * @param resId    应用中需要换肤的资源ID.
         * @return 返回对应Drawable。不需要拦截，则返回空
         */
        Drawable getDrawable(Context context, String skinName, int resId);

        /**
         * {@link #SKIN_LOADER_STRATEGY_NONE}
         * {@link #SKIN_LOADER_STRATEGY_ASSETS}
         * {@link #SKIN_LOADER_STRATEGY_BUILD_IN}
         * {@link #SKIN_LOADER_STRATEGY_PREFIX_BUILD_IN}
         *
         * @return 皮肤包加载策略类型.
         */
        int getType();
    }

    /**
     * 初始化换肤框架. 通过该方法初始化.
     *
     * @param context
     * @return
     */
    public static SkinCompatManager init(Context context) {
        if (sInstance == null) {
            synchronized (SkinCompatManager.class) {
                if (sInstance == null) {
                    sInstance = new SkinCompatManager(context);
                }
            }
        }
        return sInstance;
    }

    public static SkinCompatManager getInstance() {
        return sInstance;
    }

    /**
     * 初始化换肤框架，监听Activity生命周期.
     *
     * @param application 应用Application.
     */
    public static SkinCompatManager withoutActivity(Application application) {
        init(application);
        SkinActivityLifecycle.init(application);

        return sInstance;
    }

    private SkinCompatManager(Context context) {
        mAppContext = context.getApplicationContext();
        SkinPreference.init(context);
        initLoaderStrategy();
        initResources();

        ChangeTextSizeManager.init();

    }

    private void initLoaderStrategy() {
        // mStrategyMap.put(SKIN_LOADER_STRATEGY_NONE, new SkinNoneLoader());
        // mStrategyMap.put(SKIN_LOADER_STRATEGY_ASSETS, new SkinAssetsLoader());
        // mStrategyMap.put(SKIN_LOADER_STRATEGY_BUILD_IN, new SkinBuildInLoader());
        // mStrategyMap.put(SKIN_LOADER_STRATEGY_PREFIX_BUILD_IN, new SkinPrefixBuildInLoader());
    }

    public Context getContext() {
        return mAppContext;
    }

    /**
     * 添加皮肤包加载策略.
     *
     * @param strategy 自定义加载策略
     */
    public SkinCompatManager addStrategy(SkinLoaderStrategy strategy) {
        mStrategyMap.put(strategy.getType(), strategy);
        return this;
    }

    SparseArray<SkinLoaderStrategy> getStrategies() {
        return mStrategyMap;
    }

    /**
     * 恢复默认主题，使用应用自带资源.
     */
    public void restoreDefaultTheme(SkinLoaderListener listener) {
        loadSkin("","",listener,SKIN_LOADER_STRATEGY_NONE);
    }


    /**
     * 设置是否所有Activity都换肤.
     *
     * @param enable true: 所有Activity都换肤; false: 添加注解Skinable或实现SkinCompatSupportable的Activity支持换肤.
     * @return
     */
    public SkinCompatManager setSkinAllActivityEnable(boolean enable) {
        mSkinAllActivityEnable = enable;
        return this;
    }

    public boolean isSkinAllActivityEnable() {
        return mSkinAllActivityEnable;
    }

    /**
     * 加载记录的皮肤包，一般在Application中初始化换肤框架后调用.
     *
     * @return
     */
    public AsyncTask loadSkin(int skinVersionDtp) {

        //如果版本号不一致，直接加载官方红皮肤
        if (skinVersion != skinVersionDtp) {
            SkinPreference.getInstance().setSkinVersion(skinVersionDtp).commitEditor();
            skinVersion = skinVersionDtp;
            needClearZip = true;
            //删除内部解压的包
            boolean isNightMode = SkinPreference.getInstance().getIsNightMode();
            if (isNightMode) {
                return loadNightSkin();
            }
            return null;
        } else {
            if (isNightMode) {
                return loadNightSkin();
            }
        }
        String skin = SkinPreference.getInstance().getSkinName();
        int strategy = SkinPreference.getInstance().getSkinStrategy();
        String skinId = SkinPreference.getInstance().getSkinId();

        if (TextUtils.isEmpty(skin) || strategy == SKIN_LOADER_STRATEGY_NONE) {
            return null;
        }

        SkinInfo info = new SkinInfo();
        info.setSkinId(skinId);
        info.setSkinName(skin);
        info.setStrategy(strategy);
        return new SkinLoadTask(null, mStrategyMap.get(strategy))
                .executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, info);
    }



    public AsyncTask loadNightSkin() {
        SkinConfigEntity entity = new SkinConfigEntity();
        entity.setNeedScale(false);
        entity.setTabHeight(0);
        setSkinConfig(entity);

        SkinInfo info = new SkinInfo();
        info.setSkinName("night");
        info.setStrategy(SKIN_LOADER_STRATEGY_PREFIX_BUILD_IN);

        return new SkinLoadTask(null, mStrategyMap.get(SKIN_LOADER_STRATEGY_PREFIX_BUILD_IN))
                .executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, info);
    }

    /**
     * 加载皮肤包.
     *
     * @param skinName 皮肤包名称.
     * @param listener 皮肤包加载监听.
     * @param strategy 皮肤包加载策略.
     * @return5
     */
    public AsyncTask loadSkin(String skinName, String skinId, SkinLoaderListener listener, int
            strategy) {
        SkinLoaderStrategy loaderStrategy = mStrategyMap.get(strategy);
        if (loaderStrategy == null) {
            return null;
        }

        SkinInfo info = new SkinInfo();
        info.setSkinId(skinId);
        info.setSkinName(skinName);
        info.setStrategy(strategy);
        return new SkinLoadTask(listener, loaderStrategy).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, info);
    }

    private class SkinLoadTask extends AsyncTask<SkinInfo, Void, SkinInfo> {
        private final SkinLoaderListener mListener;
        private final SkinLoaderStrategy mStrategy;

        SkinLoadTask(@Nullable SkinLoaderListener listener, @NonNull SkinLoaderStrategy strategy) {
            mListener = listener;
            mStrategy = strategy;
        }

        @Override
        protected void onPreExecute() {
            if (mListener != null) {
                mListener.onStart();
            }
        }

        @Override
        protected SkinInfo doInBackground(SkinInfo... params) {
            synchronized (mLock) {
                while (mLoading) {
                    try {
                        mLock.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                mLoading = true;
            }
            try {
                if (params.length == 1) {
                    String skinName = mStrategy.loadSkinInBackground(mAppContext, params[0].getSkinName());
                    if (TextUtils.isEmpty(skinName)) {
                        return null;
                    } else {
                        return params[0];
                    }
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
            return null;
        }

        @Override
        protected void onPostExecute(SkinInfo skinInfo) {
            synchronized (mLock) {
                // skinName 为""时，恢复默认皮肤
                if (skinInfo != null && skinInfo.getSkinName() != null) {
                    if (skinInfo.getSkinName().equals("night")) {
                        SkinPreference.getInstance().setNightMode(true).commitEditor();
                        setIsNightMode(true);
                    } else {
                        SkinPreference.getInstance().setSkinName(skinInfo.getSkinName()).setSkinId(skinInfo.getSkinId())
                                .setSkinStrategy(mStrategy.getType())
                                .setNightMode(false).commitEditor();
                        setCurSkinId(skinInfo.getSkinId()).setIsNightMode(false);
                    }
                    notifyUpdateSkin();
                    if (mListener != null) {
                        mListener.onSuccess();
                    }
                } else {
                    //                    SkinPreference.getInstance().setSkinName("").setSkinStrategy
                    // (SKIN_LOADER_STRATEGY_NONE)
                    //                                  .commitEditor();
                    if (mListener != null) {
                        mListener.onFailed("皮肤资源获取失败");
                    }


                }
                mLoading = false;
                mLock.notifyAll();
            }
        }
    }

    /**
     * 获取皮肤包包名.
     *
     * @param skinPkgPath sdcard中皮肤包路径.
     * @return
     */
    public String getSkinPackageName(String skinPkgPath) {
        PackageManager mPm = mAppContext.getPackageManager();
        PackageInfo info = mPm.getPackageArchiveInfo(skinPkgPath, PackageManager.GET_ACTIVITIES);
        return info.packageName;
    }

    /**
     * 获取皮肤包资源{@link Resources}.
     *
     * @param skinPkgPath sdcard中皮肤包路径.
     * @return
     */
    @Nullable
    public Resources getSkinResources(String skinPkgPath) {
        try {
            PackageInfo packageInfo = mAppContext.getPackageManager().getPackageArchiveInfo(skinPkgPath, 0);
            packageInfo.applicationInfo.sourceDir = skinPkgPath;
            packageInfo.applicationInfo.publicSourceDir = skinPkgPath;
            Resources res = mAppContext.getPackageManager().getResourcesForApplication(packageInfo.applicationInfo);
            Resources superRes = mAppContext.getResources();
            return new Resources(res.getAssets(), superRes.getDisplayMetrics(), superRes.getConfiguration());
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    /*****************************  供外部查询和设置当前皮肤信息  *******************************/
    private boolean useFilter = false;
    private boolean isNightMode = false;
    private int skinVersion = 1;
    private String curSkinId;

    private void initResources() {
        useFilter = SkinPreference.getInstance().getUseFilter();
        isNightMode = SkinPreference.getInstance().getIsNightMode();
        skinVersion = SkinPreference.getInstance().getSkinVersion();
        curSkinId = SkinPreference.getInstance().getSkinId();
    }

    /**
     * 获取当前皮肤包.
     */
    public String getCurSkinId() {
        return curSkinId;
    }

    private SkinCompatManager setCurSkinId(String curSkinId) {
        this.curSkinId = curSkinId;
        return this;
    }

    /**
     * 是否使用夜间模式中
     */
    public boolean isInNightMode() {
        return isNightMode;
    }

    private SkinCompatManager setIsNightMode(boolean isNightMode) {
        this.isNightMode = isNightMode;
        return this;
    }



    /**
     * 设置是否使用黑白滤镜
     */
    public void useFilter(boolean useFilter) {
        this.useFilter = useFilter;

        SkinCompatResources.getInstance().clear();
        SkinPreference.getInstance().setUseFilter(useFilter);
    }

    public boolean isUseFilter() {
        return useFilter;
    }

    public int getSkinVersion() {
        return skinVersion;
    }

    public SkinCompatManager setSkinVersion(int skinVersion) {
        this.skinVersion = skinVersion;
        return this;
    }

    /**
     * 用来标记是否需要清空皮肤包版本
     *
     * @return
     */
    public boolean needClearZip() {
        return needClearZip;
    }

    /**
     * 用来标记是否需要清空皮肤包版本
     *
     * @return
     */
    public void setClearZipEnd() {
        needClearZip = false;
    }

}